package com.bsj.power.pls.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bsj.power.common.config.cached.BindCardCached;
import com.bsj.power.common.config.cached.LocationDeviceCached;
import com.bsj.power.common.config.cached.PersonnelCached;
import com.bsj.power.common.config.exception.ApiException;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.def.dto.cardReport.BindCardDTO;
import com.bsj.power.common.def.dto.cardReport.CardReportSearchDTO;
import com.bsj.power.common.def.dto.cardReport.PersonalCardReportDTO;
import com.bsj.power.common.def.entity.cardReport.CardReport;
import com.bsj.power.common.def.vo.KeyValueVO;
import com.bsj.power.common.def.vo.pls.BindCardStatisticsVO;
import com.bsj.power.common.def.vo.pls.CardReportVO;
import com.bsj.power.common.def.vo.pls.PersonalCardReportInfoVO;
import com.bsj.power.common.def.vo.pls.excel.CardReportExcelVO;
import com.bsj.power.common.mapper.CardReportMapper;
import com.bsj.power.common.util.DateUtils;
import com.bsj.power.common.util.ParamCheckUtil;
import com.bsj.power.common.util.StringUtils;
import com.bsj.power.pls.service.CardReportService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.bsj.power.common.util.DateUtils.yearMonthDay;

/**
 * @author LiJiaXin
 * @version 1.0.0
 * @description CardReportServiceImpl
 * @time 2024/4/23 20:02
 */
@Service
public class CardReportServiceImpl implements CardReportService {

    @Resource
    private CardReportMapper cardReportMapper;

    @Autowired
    private PersonnelCached personnelCached;

    @Autowired
    private LocationDeviceCached locationDeviceCached;

    @Autowired
    private BindCardCached bindCardCached;

    /**
     * 智慧领卡报表
     *
     * @param cardReportSearchDTO
     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.vo.pls.CardReportVO>>
     * @author ljx
     * @time 2024/4/23 20:10
     */
    @Override
    public JsonResult<List<CardReportVO>> pageCardReport(CardReportSearchDTO cardReportSearchDTO) {
        List<CardReportVO> cardReportVOS = new LinkedList<>();
        long total = cardReportMapper.countCardReport(cardReportSearchDTO);
        if (total == NumericalConstants.ZERO) {
            return JsonResult.success(cardReportVOS, total);
        }
        cardReportSearchDTO.initPageNumber();
        cardReportSearchDTO.setSearchType(NumericalConstants.ONE);
        return JsonResult.success(cardReportMapper.pageCardReport(cardReportSearchDTO), total);
    }

    /**
     * 获取导出数据
     *
     * @param cardReportSearchDTO
     * @return java.util.List<com.bsj.power.common.def.vo.pls.excel.CardReportExcelVO>
     * @author ljx
     * @time 2024/5/10 16:23
     */
    @Override
    public List<CardReportExcelVO> getExportData(CardReportSearchDTO cardReportSearchDTO) {
        cardReportSearchDTO.setSearchType(NumericalConstants.TWO);
        List<CardReportVO> cardReportVOS = cardReportMapper.pageCardReport(cardReportSearchDTO);
        return cardReportVOS.stream().map(cardReportVO -> {
            CardReportExcelVO cardReportExcelVO = new CardReportExcelVO();
            BeanUtils.copyProperties(cardReportVO, cardReportExcelVO);
            cardReportExcelVO.setType(cardReportVO.getType().equals(NumericalConstants.ONE) ? "绑卡" : "退卡");
            cardReportExcelVO.setClassify(cardReportVO.getClassify().equals(NumericalConstants.ZERO) ? "负责人" : "作业人员");
            cardReportExcelVO.setIsRepetitionName(cardReportVO.getIsRepetitionName().equals(NumericalConstants.ONE) ? "是" : "否");
            return cardReportExcelVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<PersonalCardReportInfoVO> listPersonalCardReportInfo(PersonalCardReportDTO dto) {
        QueryWrapper<CardReport> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(dto.getName())) {
            queryWrapper.eq("personnel_name", dto.getName());
        }
        if (!StringUtils.isEmpty(dto.getEmpNo())) {
            queryWrapper.eq("emp_no", dto.getEmpNo());
        }
        if (!StringUtils.isEmpty(dto.getBeginTime()) && !StringUtils.isEmpty(dto.getEndTime())) {
            queryWrapper.between("create_time", dto.getBeginTime(), dto.getEndTime());
        }
        List<CardReport> cardReportList = cardReportMapper.selectList(queryWrapper);
        // 把这个cardReportList重新组织一下
        // 按设备号进行分组，按时间进行排序
        Map<String, List<CardReport>> locationDeviceIdMap = cardReportList.stream()
                .collect(Collectors.groupingBy(CardReport::getDeviceName));

        List<PersonalCardReportInfoVO> vos = new ArrayList<>();
        for (Map.Entry<String, List<CardReport>> stringListEntry : locationDeviceIdMap.entrySet()) {
            String key = stringListEntry.getKey();
            List<CardReport> value = stringListEntry.getValue();
            List<CardReport> sortedList = value.stream().sorted(Comparator.comparing(CardReport::getCreateTime))
                    .collect(Collectors.toList());
            for (int i = 0; i < sortedList.size(); i++) {
                CardReport front = sortedList.get(i);
                // 类型是退卡就跳过，从绑卡开始处理
                if (front.getType() == 2) {
                    continue;
                }
                // 执行到这里，说明这一条是绑卡
                if (i + 1 < sortedList.size()) {
                    CardReport back = sortedList.get(i + 1);
                    // 上一条是绑卡，后一条还是绑卡，上一条就不管了，看这一条后面还有没有数据，有数据这条就不管了，没有数据就把这条数据返回
                    if (back.getType() == 1) {
                        if (i + 2 <= sortedList.size()) {
                            continue;
                        }
                        PersonalCardReportInfoVO vo = new PersonalCardReportInfoVO();
                        BeanUtils.copyProperties(back, vo);
                        vo.setBindTime(DateUtils.dateToStr(back.getCreateTime()));
                        vo.setUnBindTime(DateUtils.dateToStr(DateUtils.getEndOfDay(back.getCreateTime())));
                        vos.add(vo);
                    } else {
                        PersonalCardReportInfoVO vo = new PersonalCardReportInfoVO();
                        BeanUtils.copyProperties(front, vo);
                        vo.setBindTime(DateUtils.dateToStr(front.getCreateTime()));
                        vo.setUnBindTime(DateUtils.dateToStr(back.getCreateTime()));
                        vos.add(vo);
                    }
                } else {
                    // 这里说明这一条是绑卡，而且后面没有数据了，就把这一条的组织一下
                    PersonalCardReportInfoVO vo = new PersonalCardReportInfoVO();
                    BeanUtils.copyProperties(front, vo);
                    vo.setBindTime(DateUtils.dateToStr(front.getCreateTime()));
                    vo.setUnBindTime(DateUtils.dateToStr(DateUtils.getEndOfDay(front.getCreateTime())));
                    vos.add(vo);
                }
            }
        }


        return vos;
    }

    /**
     * 绑卡信息相关统计
     *
     * @return com.bsj.power.common.def.vo.pls.BindCardStatisticsVO
     * @author ljx
     * @time 2024/12/18 19:40
     */
    @Override
    public BindCardStatisticsVO statistics() {
        BindCardStatisticsVO bindCardStatisticsVO = new BindCardStatisticsVO();
        List<BindCardDTO> bindCardDTOS = bindCardCached.hgetAllBindCard();
        if (CollectionUtils.isEmpty(bindCardDTOS)) {
            return bindCardStatisticsVO;
        }
        Map<Integer, Long> longMap = bindCardDTOS.stream().filter(bindCardDTO -> bindCardDTO.getBindWay() != null)
                .collect(Collectors.groupingBy(BindCardDTO::getBindWay, Collectors.counting()));
        if (!CollectionUtils.isEmpty(longMap)) {
            bindCardStatisticsVO.setManualNumber(longMap.get(NumericalConstants.ONE));
            bindCardStatisticsVO.setAutomaticNumber(longMap.get(NumericalConstants.TWO));
        }
        Date date = new Date();
        String startTime = DateUtils.getStartOfDay2(date);
        String endTime = DateUtils.getEndOfDay2(date);
        Long bindTotal = cardReportMapper.selectCount(Wrappers.<CardReport>lambdaQuery()
                .between(CardReport::getCreateTime, startTime, endTime)
                .eq(CardReport::getType, NumericalConstants.ONE));
        bindCardStatisticsVO.setBindTotal(bindTotal);
        return bindCardStatisticsVO;
    }

    /**
     * 绑卡趋势
     *
     * @param startTime
     * @param endTime
     * @param type      1月统计 2日统计
     * @return com.bsj.power.common.config.global.JsonResult<java.util.Map < java.lang.String, java.lang.Long>>
     * @author ljx
     * @time 2024/12/19 16:10
     */
    @Override
    public Map<String, Long> listNumberByTime(String startTime, String endTime, Integer type) throws ParseException {
        ParamCheckUtil.isAnyBlank(startTime, endTime);
        ParamCheckUtil.isNull(type);
        if (DateUtils.compareDate(startTime, endTime)) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        String timeFormat = "%Y-%m";
        int value = DateUtils.getMonthsDifference(startTime, endTime);
        if (type.equals(NumericalConstants.ONE)) {
            if (value > 12) {
                throw new ApiException(JsonResultEnum.TOO_MUCH_MONTH_SPAN);
            }
        } else if (type.equals(NumericalConstants.TWO)) {
            Date startDate = DateUtils.strToDate(yearMonthDay, startTime);
            Date entDate = DateUtils.strToDate(yearMonthDay, endTime);
            value = DateUtils.differentDays(startDate, entDate) + NumericalConstants.ONE;
            if (value > 30) {
                throw new ApiException(JsonResultEnum.TOO_MUCH_DAY_SPAN);
            }
            timeFormat = "%Y-%m-%d";
        } else {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        Map<String, Long> resultMap = getDateTimeKey(endTime, type, value);
        startTime = startTime + " 00:00:00";
        endTime = endTime + " 23:59:59";
        CardReportSearchDTO cardReportSearchDTO = new CardReportSearchDTO(startTime, endTime, timeFormat);
        List<KeyValueVO> keyValueVOS = cardReportMapper.cardBindTimeCount(cardReportSearchDTO);
        keyValueVOS.forEach(keyValueVO -> {
            resultMap.put(keyValueVO.getKeyStr(), Long.parseLong(keyValueVO.getStrValue()));
        });
        return resultMap;
    }

    /**
     * 组装日期时间的key值
     *
     * @param endTime
     * @param type
     * @param value
     * @return java.util.Map<java.lang.String, java.lang.Long>
     * @author ljx
     * @time 2024/12/19 16:45
     */
    private static Map<String, Long> getDateTimeKey(String endTime, Integer type, Integer value) {
        Map<String, Long> resultMap = new HashMap<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(yearMonthDay);
        LocalDate localDate = LocalDate.parse(endTime, formatter);
        LocalDate temp;
        String key;
        for (int i = 0; i < value; i++) {
            if (type == 1) {
                temp = localDate.minusMonths(i);
                key = temp.toString().substring(0, 7);
            } else {
                temp = localDate.minusDays(i);
                key = temp.toString().substring(0, 10);
            }
            resultMap.put(key, 0L);
        }
        return new TreeMap<>(resultMap);
    }
}
